home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Collection of Tools & Utilities
/
Collection of Tools and Utilities.iso
/
edit
/
xvisrc.zip
/
MISCCMDS.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-07-28
|
11KB
|
521 lines
/* Copyright (c) 1990,1991,1992 Chris and John Downey */
#ifndef lint
static char *sccsid = "@(#)misccmds.c 2.2 (Chris & John Downey) 8/28/92";
#endif
/***
* program name:
xvi
* function:
PD version of UNIX "vi" editor, with extensions.
* module name:
misccmds.c
* module function:
Miscellaneous functions.
This module will probably get hacked later and split
up more sensibly.
* history:
STEVIE - ST Editor for VI Enthusiasts, Version 3.10
Originally by Tim Thompson (twitch!tjt)
Extensive modifications by Tony Andrews (onecom!wldrdg!tony)
Heavily modified by Chris & John Downey
***/
#include "xvi.h"
/*
* Add a blank line above or below the current line.
* Returns TRUE for success, FALSE for failure to get memory.
*
* The single boolean parameter tells us whether to split the
* current line at the cursor position, or just to open a new
* line leaving the current one intact.
*/
bool_t
openfwd(split_line)
bool_t split_line;
{
Line *l; /* pointer to newly allocated line */
register Posn *oldposn;
register Line *oldline;
register char *otext;
oldposn = curwin->w_cursor;
oldline = oldposn->p_line;
otext = oldline->l_text;
/*
* First find space for new line.
*
* By asking for as much space as the prior line had we make sure
* that we'll have enough space for any auto-indenting.
*/
l = newline(strlen(otext) + SLOP);
if (l == NULL)
return(FALSE);
/*
* Link the new line into the list.
*/
repllines(curwin, oldline->l_next, 0L, l);
/*
* Do auto-indent.
*/
if (Pb(P_autoindent)) {
*l->l_text = '\0';
indentchars = set_indent(l, get_indent(oldline));
} else {
indentchars = 0;
}
/*
* If we're in insert mode, we need to move the remainder of the
* current line onto the new line. Otherwise the new line is left
* blank.
*/
if (split_line) {
char *s;
s = otext + oldposn->p_index;
replchars(curwin, l, indentchars, 0, s);
replchars(curwin, oldline, oldposn->p_index, strlen(s), "");
}
/*
* Move cursor to the new line.
*/
move_cursor(curwin, l, indentchars);
move_window_to_cursor(curwin);
cursupdate(curwin);
update_buffer(curbuf);
return(TRUE);
}
/*
* Add a blank line above the current line.
* Returns TRUE for success, FALSE for failure to get memory.
*/
bool_t
openbwd()
{
Line *l;
register Line *oldline;
register char *otext;
oldline = curwin->w_cursor->p_line;
otext = oldline->l_text;
/*
* First find space for new line.
*/
l = newline(strlen(otext) + SLOP);
if (l == NULL)
return(FALSE);
/*
* Link the new line into the list.
*/
repllines(curwin, oldline, 0L, l);
/*
* Do auto-indent.
*/
if (Pb(P_autoindent)) {
*l->l_text = '\0';
indentchars = set_indent(l, get_indent(oldline));
} else {
indentchars = 0;
}
/*
* Ensure the cursor is pointing at the right line.
*/
move_cursor(curwin, l, indentchars);
move_window_to_cursor(curwin);
cursupdate(curwin);
update_buffer(curbuf);
return(TRUE);
}
/*
* Count the number of lines between the two given lines.
* If the two given lines are the same, the return value
* is 1, not 0; i.e. the count is inclusive.
*
* Note that this function has been changed to give the
* correct number of lines, even if they are ordered wrongly.
* This change is backwards-compatible with the old version.
*/
long
cntllines(pbegin, pend)
Line *pbegin;
register Line *pend;
{
register Line *lp;
register long lnum;
bool_t swapped = FALSE;
/*
* Ensure correct ordering.
*/
if (later(pbegin, pend)) {
lp = pbegin;
pbegin = pend;
pend = lp;
swapped = TRUE;
}
for (lnum = 1, lp = pbegin; lp != pend; lp = lp->l_next) {
lnum++;
}
if (swapped)
lnum = - lnum;
return(lnum);
}
/*
* plines(lp) - return the number of physical screen lines taken by line 'lp'.
*/
long
plines(win, lp)
Xviwin *win;
Line *lp;
{
register long col;
register char *s;
s = lp->l_text;
if (*s == '\0') /* empty line */
return(1);
/*
* If list mode is on, then the '$' at the end of
* the line takes up one extra column.
*/
col = Pb(P_list) ? 1 : 0;
if (Pb(P_number)) {
col += NUM_SIZE;
}
for ( ; *s != '\0'; s++) {
col += vischar(*s, (char **) NULL, (int) col);
}
{
register int row;
register int columns;
columns = win->w_ncols;
for (row = 1; col > columns; ) {
row++;
col -= columns;
}
return row;
}
}
/*
* Count the number of physical lines between the two given lines.
*
* This routine is like cntllines(), except that:
* it counts physical rather than logical lines
* it always returns the absolute number of physical lines
* it is non-inclusive
* if the physical line count for a group of lines is greater
* than or equal to rows * 2, we just return rows * 2; we assume
* the caller isn't interested in the exact number.
*/
long
cntplines(win, pbegin, pend)
Xviwin *win;
Line *pbegin;
register Line *pend;
{
register Line *lp;
register long physlines;
unsigned toomuch;
/*
* Ensure correct ordering.
*/
if (later(pbegin, pend)) {
lp = pbegin;
pbegin = pend;
pend = lp;
}
toomuch = win->w_nrows * 2;
for (physlines = 0, lp = pbegin; lp != pend; lp = lp->l_next) {
physlines += plines(win, lp);
if (physlines >= toomuch)
break;
}
return(physlines);
}
/*
* gotoline(buffer, n) - return a pointer to line 'n' in the given buffer
*
* Returns the first line of the file if n is 0.
* Returns the last line of the file if n is beyond the end of the file.
*/
Line *
gotoline(b, n)
Buffer *b;
register unsigned long n;
{
if (n == 0) {
return(b->b_file);
} else {
register Line *lp;
for (lp = b->b_file; --n > 0 && lp->l_next != b->b_lastline;
lp = lp->l_next) {
;
}
return(lp);
}
}
int
get_indent(lp)
register Line *lp;
{
register char *text;
register int indent;
register int ts = Pn(P_tabstop); /* synonym for efficiency */
if (lp == NULL || (text = lp->l_text) == NULL) {
show_error(curwin, "Internal error: get_indent(NULL)");
return 0;
}
for (indent = 0; *text != '\0' && (*text == ' ' || *text == '\t');
text++) {
indent += *text == ' ' ? 1 : ts - indent % ts;
}
return indent;
}
/*
* Set number of columns of leading whitespace on line, regardless of
* what was there before, & return number of characters (not columns)
* used.
*/
int
set_indent(lp, indent)
Line *lp;
register int indent;
{
register char *cp; /* temp char pointer for loops */
register int ntabs; /* number of tabs to use */
unsigned nnew; /* no of chars used in old line */
unsigned nold; /* no of chars used in new version */
char *newstr; /* allocated string for new indent */
if (lp == NULL || lp->l_text == NULL) {
show_error(curwin, "Internal error: set_indent(0)");
return(0);
}
/*
* Find out how many tabs we need, & how many spaces.
*/
for (ntabs = 0; indent >= Pn(P_tabstop); ntabs++)
indent -= Pn(P_tabstop);
/*
* Find out how many characters were used for initial
* whitespace in the current (old) line.
*/
for (cp = lp->l_text; *cp == ' ' || *cp == '\t'; cp++) {
;
}
nold = cp - lp->l_text;
/*
* "nnew" is the number of characters we will use
* for indentation in the new version of the line.
*/
nnew = ntabs + indent;
/*
* Get some space, and place into it the string of tabs
* and spaces which will form the new indentation.
* If no space available, return nold as we have not
* changed the line; this is the correct action.
*/
newstr = alloc((unsigned) nnew + 1);
if (newstr == NULL)
return(nold);
cp = newstr;
while (ntabs-- > 0)
*cp++ = '\t';
while (indent-- > 0)
*cp++ = ' ';
*cp = '\0';
/*
* Finally, replace the old with the new.
*/
replchars(curwin, lp, 0, (int) nold, newstr);